import React, { createContext, useContext, useEffect, useRef, useState } from "react";
import { getId } from "../../utils/commonUtil"
import "./checkbox-group.scss"

/**
 * @param size 多选框组尺寸
 * @param disabled 是否禁用
 * @param min 可被勾选的 checkbox 的最小数量
 * @param max 可被勾选的 checkbox 的最大数量
 * @param children 插槽
 * @param defaultValue 默认选中值
 * @param value 选中的值
 */
interface GroupProps {
    size?: 'default' | 'small' | 'large',
    disabled?: boolean,
    min?: number,
    max?: number,
    children?: React.ReactNode,
    defaultValue?: Array<string | number> | boolean,
    value?: Array<string | number> | boolean
    change?: (value: Array<string | number> | boolean) => void
}

const Value = createContext<any>({})
const sizeArr = ['small', 'large']

const CheckboxGroup = ({ size, disabled = false, min, max, children, defaultValue = [], value = [], change = () => { } }: GroupProps) => {
    const [id] = useState<string>(`pe-checkbox-${getId()}`)

    const checkboxGroupRef = useRef<HTMLDivElement>(null)

    const [modelValue, setModelValue] = useState<Array<string | number> | boolean>(defaultValue)

    // 禁用多选框
    const [disabledArr, setDisabledArr] = useState<Array<string | number>>([])

    const [checkboxSize, setCheckboxSize] = useState<'default' | 'small' | 'large'>()
    const [checkboxDisabled, setCheckboxDisabled] = useState<boolean>(false)

    useEffect(() => {
        setModelValue(value)
    }, [value])

    useEffect(() => {
        setCheckboxSize(size)
        setCheckboxDisabled(disabled)
        setDisabledArr([])
        if (modelValue instanceof Array) {
            const size1 = modelValue.length
            if (typeof min === "number") {
                if (size1 >= min) {
                    let arr = []
                    for (let i = 0; i < min; i++) {
                        arr.push(modelValue[i])
                    }
                    setDisabledArr(arr)
                }
            }
            if (typeof max === "number") {
                if (size1 >= max) {
                    const flag = typeof modelValue[0] === 'number'
                    let arr: Array<string | number> = []
                    const inputList = checkboxGroupRef.current?.querySelectorAll<HTMLInputElement>(`[name=${id}]`)
                    inputList?.forEach(item => {
                        if (item.checked) {
                            item.disabled = false
                        } else {
                            if (flag) {
                                arr.push(Number(item.value))
                            } else {
                                arr.push(item.value)
                            }
                        }
                    })
                    setDisabledArr(arr)
                }
            }
        }
    }, [size, disabled, min, max, modelValue])

    return (
        <div ref={checkboxGroupRef} className="pe-checkbox-group" id={id}>
            <Value.Provider value={{ modelValue, setModelValue, checkboxName: id, checkboxSize, checkboxDisabled, disabledArr, setDisabledArr, change }}>
                {children}
            </Value.Provider>
        </div>
    )
}

/**
 * @param value 选中状态的值（只有在checkbox-group或者绑定对象类型为array时有效）
 * @param label 选中状态的值，只有在绑定对象类型为 array 时有效。
 * @param disabled 是否禁用
 * @param size Checkbox 的尺寸
 * @param border 是否显示边框
 * @param name 原生 name 属性
 * @param indeterminate 设置不确定状态，仅负责样式控制
 * @param defaultValue 默认值
 */
interface CheckboxProps {
    value: string | number,
    label?: string | number,
    disabled?: boolean,
    size?: 'default' | 'small' | 'large'
    border?: boolean,
    name?: string,
    indeterminate?: boolean,
    defaultValue?: boolean
    children?: React.ReactNode,
    onChange?: (value: boolean) => void,
    className?: string
}

const Checkbox = ({
    value,
    label,
    disabled = false,
    size = "default",
    border = false,
    name,
    indeterminate = false,
    defaultValue,
    children,
    onChange = () => { },
    className
}: CheckboxProps) => {
    const { modelValue = [], setModelValue, disabledArr = [], checkboxSize, checkboxDisabled = false, checkboxName, change = () => { } } = useContext(Value)

    const [modelValue1, setModelValue1] = useState<boolean>(typeof defaultValue === 'boolean' ? defaultValue : false)

    const [checkboxSize1, setCheckboxSize1] = useState<'default' | 'small' | 'large'>("default")
    const [checkboxDisabled1, setCheckboxDisabled1] = useState<boolean>(false)

    const [indeterminateValue, setIndeterminateValue] = useState<boolean>(false)

    const [checkboxName1, setCheckboxName1] = useState<string>(checkboxName)

    useEffect(() => {
        if (typeof defaultValue === 'boolean') {
            setModelValue1(defaultValue)
        }
    }, [defaultValue])

    useEffect(() => {
        if (checkboxSize) {
            setCheckboxSize1(checkboxSize)
        } else {
            setCheckboxSize1(size)
        }
        if (checkboxDisabled) {
            setCheckboxDisabled1(true)
        } else {
            setCheckboxDisabled1(disabled)
        }
        if (name) {
            setCheckboxName1(name)
        }
        setIndeterminateValue(indeterminate)
    }, [size, disabled, name, indeterminate, checkboxSize, checkboxDisabled])
    return (
        <label className={["pe-checkbox", className, modelValue1 || modelValue.includes(value) ? 'pe-checkbox-active' : '', checkboxDisabled1 || disabledArr.includes(value) ? 'pe-checkbox-disabled' : '', sizeArr.includes(checkboxSize1) ? `pe-checkbox-${checkboxSize1}` : '',
            border ? 'pe-checkbox-border' : '', indeterminateValue ? 'pe-checkbox-indeterminate' : ''].join(" ").trim()}>
            <div className="pe-checkbox-item">
                {
                    typeof defaultValue !== "boolean" ? (
                        <input className="pe-checkbox-inp" type="checkbox" name={checkboxName1}
                            onChange={(e) => {
                                if (e.target.checked) {
                                    const arr = JSON.parse(JSON.stringify(modelValue))
                                    arr.push(value)
                                    change(arr)
                                    setModelValue(arr)
                                } else {
                                    setModelValue(modelValue.filter((item: string | number) => item !== value))
                                    change(modelValue.filter((item: string | number) => item !== value))
                                }
                            }} value={value} disabled={checkboxDisabled1 || disabledArr.includes(value)} />
                    ) : (
                        <input className="pe-checkbox-inp" type="checkbox" disabled={checkboxDisabled1}
                            onChange={(e) => {
                                setModelValue1(e.target.checked)
                                onChange(e.target.checked)
                            }} name={checkboxName1} />
                    )
                }
                <div className="pe-checkbox-square">
                    {
                        !indeterminateValue ? (
                            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
                                <path fill="currentColor"
                                    d="M406.656 706.944 195.84 496.256a32 32 0 1 0-45.248 45.248l256 256 512-512a32 32 0 0 0-45.248-45.248L406.592 706.944z">
                                </path>
                            </svg>
                        ) : (
                            <span>-</span>
                        )
                    }
                </div>
            </div>
            {
                label || children || children === 0 ? (
                    <div className="pe-checkbox-content">
                        {
                            children || children === 0 ? (<>{children}</>) : (<>{label}</>)
                        }
                    </div>
                ) : null
            }
        </label>
    )
}

interface ButtonProps {
    value: string | number,
    label?: string | number,
    disabled?: boolean,
    name?: string,
    defaultValue?: boolean,
    children?: React.ReactNode
    onChange?: (value: boolean) => void,
    className?: string
}
const CheckboxButton = ({
    value,
    label,
    disabled = false,
    name,
    defaultValue,
    children,
    onChange = () => { },
    className
}: ButtonProps) => {
    const { modelValue = [], setModelValue, disabledArr = [], checkboxSize, checkboxDisabled = false, checkboxName, change = () => { } } = useContext(Value)

    const [modelValue1, setModelValue1] = useState<boolean>(typeof defaultValue === 'boolean' ? defaultValue : false)

    const [checkboxDisabled1, setCheckboxDisabled1] = useState<boolean>(false)

    const [checkboxName1, setCheckboxName1] = useState<string>(checkboxName)

    useEffect(() => {
        if (typeof defaultValue === 'boolean') {
            setModelValue1(defaultValue)
        }
    }, [defaultValue])

    useEffect(() => {
        if (checkboxDisabled) {
            setCheckboxDisabled1(true)
        } else {
            setCheckboxDisabled1(disabled)
        }
        if (name) {
            setCheckboxName1(name)
        }
    }, [disabled, name, checkboxDisabled])

    return (
        <div
            className={["pe-checkbox-button", className,
                modelValue1 || modelValue.includes(value) ? 'pe-checkbox-button-active' : '',
                checkboxDisabled1 || disabledArr.includes(value) ? 'pe-checkbox-button-disabled' : '',
                sizeArr.includes(checkboxSize) ? `pe-checkbox-button-${checkboxSize}` : ''].join(" ").trim()}>
            {
                typeof defaultValue !== "boolean" ? (
                    <input className="pe-checkbox-inp" type="checkbox" name={checkboxName1}
                        onChange={(e) => {
                            if (e.target.checked) {
                                const arr = JSON.parse(JSON.stringify(modelValue))
                                arr.push(value)
                                change(arr)
                                setModelValue(arr)
                            } else {
                                setModelValue(modelValue.filter((item: string | number) => item !== value))
                                change(modelValue.filter((item: string | number) => item !== value))
                            }
                        }}
                        value={value} disabled={checkboxDisabled1 || disabledArr.includes(value)} />
                ) : (
                    <input className="pe-checkbox-inp" type="checkbox" disabled={checkboxDisabled1}
                        onChange={(e) => {
                            setModelValue1(e.target.checked)
                            onChange(e.target.checked)
                        }}
                        name={checkboxName1} />
                )
            }
            <div className="pe-checkbox-button-content">
                {
                    children || children === 0 ? (<>{children}</>) : (<>{label}</>)
                }
            </div>
        </div>
    )
}

export { CheckboxGroup, Checkbox, CheckboxButton }